package com.liangdemo.web.test.thread;

import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 线程池
 *
 * @author: LiangErLe
 * @date: 2022/9/27
 **/
public class ThreadPoolDemo {
    /**
     * newCachedThreadPool（）
     * 缓存型线程池，先查看池中有没有以前创建的线程，如果有，就重用，如果没有就创建一个新的线程并加入到线程池中。
     * 如果线程池长度超过处理需求，可灵活回收线程，若无线程，则创建新的线程
     * <p>
     * 重用：缓存性池子，先查看线程池中有没有以前生成的线程，如果有就reuse（重用），如果没有就创建一个新的线程
     * 使用场景：用于执行一些生存期很短的异步型任务，因此在一个面向链接的daemon（守护线程）型server中用的不多
     * 超时：能reuse的线程，必须是timeout IDLE（超时空闲）内的池中的线程，缺省timeout是60s，超过这个IDLE时长，线程实例将被终止及移出线程池
     * 结束：放入CachedThreadPool（缓存线程池）的线程不必担心其结束，超过timeout(超时)不活动，会自动关闭
     */
    public void test1() {
        ExecutorService exe = Executors.newCachedThreadPool();
        //创建5条线程s
        for (int i = 1; i < 6; i++) {
            final int taskID = i;
            exe.execute(new Runnable() {
                @Override
                public void run() {
                    //线程执行次数
                    for (int j = 1; j < 4; j++) {
                        try {
                            Thread.sleep(500);
                            System.out.println("线程id：" + taskID + ",执行第" + j + "次");
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            });
        }
    }

    /**
     * newFixedThreadPool(定长线程池)
     * 可控线程最大的并发数，
     * 如当前执行的任务超过线程池的大小，多出的线程就会进入等待状态，知道有空闲的线程执行任务，
     * 如当前执行的任务小于线程池的大小，线程池中空闲的线程并不会销毁
     * <p>
     * 重用：查看当前线程池中是否有空闲线程，能reuse（重用）就重用，如果没有不会创建新的线程
     * 固定项目：任意活动时间点，最多只能有固定数目的活动线程存在，此时有如果有新的线程要建立，只能放在另外的队列中等待，直到当前的线程中某个线程终止直接被移除池子
     * 超时：没有IDLE（空闲）机制，
     * 使用场景：针对一些很稳定很固定的正规并发线程，多用于服务器
     */
    public void test2() {
        ExecutorService exe = Executors.newFixedThreadPool(3);
        for (int i = 1; i < 6; i++) {
            final int taskID = i;
            exe.execute(new Runnable() {
                @Override
                public void run() {
                    //线程执行次数
                    for (int j = 1; j < 4; j++) {
                        try {
                            Thread.sleep(500);
                            System.out.println("线程id：" + taskID + ",执行第" + j + "次");
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            });
        }
        exe.shutdownNow();
    }

    /**
     * newScheduledThreadPool(调度型线程池） 支持定时及周期性任务执行，也是一个固定长度的线程池
     * 使用方法为：
     * ScheduledExecutorService exe= Executors.newScheduledThreadPool(3);
     */
    public void test3() {
        ScheduledExecutorService exe = Executors.newScheduledThreadPool(3);
        for (int i = 1; i < 6; i++) {
            final int taskID = i;
            //scheduleAtFixedRate后面的参数 0 表示立即执行，2表示2秒执行一次调度。执行结果：
            exe.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                        System.out.println("线程id：" + taskID + ",时间为：" + LocalDateTime.now() + "执行一次");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }, 0, 2, TimeUnit.SECONDS);
        }
    }

    /**
     * newSingleThreadExecutor(单线程话线程)
     * 它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序（FIFO（先进先出），LIFO（后进先出），优先级）执行。
     * 如当前线程意外终止，会创建一个新线程继续执行任务，和直接创建线程不同，也和newFixedThreadPool(1)不同
     * 使用方法为：
     * ExecutorService exe= Executors.newSingleThreadExecutor();
     */
    public void test4() {
        ExecutorService exe = Executors.newSingleThreadExecutor();
        for (int i = 1; i < 6; i++) {
            final int taskID = i;
            exe.execute(new Runnable() {
                public void run() {
                    for (int j = 1; j < 4; j++) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程ID：" + taskID + "，执行第 " + j + " 次");
                    }
                }
            });
        }
        //执行完关闭线程
        exe.shutdown();
    }

    public static void main(String[] args) {
        ThreadPoolDemo demo = new ThreadPoolDemo();
        demo.test4();
    }
}
